import { CoreCommand } from "./corecmd";
import { HashCommand } from "./hashcmd";
import { ListCommand } from "./listcmd";
import { SetCommand } from "./setcmd";
import { SortedSetCommand } from "./sortsetcmd";
import { StrCommand } from "./strcmd";
import type { OpenPostOperationRequest } from "./swagger";
import { CmdApi, ConnectionApi, Configuration } from "./swagger";


export class RedisClient {
    constructor(proxyAddr: string, proxyToken: string, connId: string = "", name: string = "", dbIndex: number = 0) {
        this.proxyToken = proxyToken;
        const cfg = new Configuration({ basePath: `http://${proxyAddr}` });
        this.connectionApi = new ConnectionApi(cfg);
        this.cmdApi = new CmdApi(cfg);
        this.connId = connId;
        this.name = name;
        this.dbIndex = dbIndex;
    }

    private readonly proxyToken: string;
    private connId: string;
    private name: string;
    private dbIndex: number;
    private readonly cmdApi: CmdApi;
    private readonly connectionApi: ConnectionApi;

    async connect(req: OpenPostOperationRequest): Promise<void> {
        if (this.connId !== "") {
            return;
        }
        if (req.openPostRequest !== undefined) {
            req.openPostRequest.token = this.proxyToken;
        }
        this.connId = await this.connectionApi.openPost(req);
        this.name = req.openPostRequest?.name ?? "";
        this.dbIndex = req.openPostRequest?.db ?? 0;
    }

    isConnected(): boolean {
        return this.connId !== "";
    }

    async close(): Promise<void> {
        if (this.connId === "") {
            return;
        }
        await this.connectionApi.closePost({
            closePostRequest: {
                token: this.proxyToken,
                id: this.connId,
            },
        });
        this.connId = "";
    }

    getConnId(): string {
        return this.connId;
    }

    getName(): string {
        return this.name;
    }

    getDbIndex(): number {
        return this.dbIndex;
    }

    async exec(...args: string[]): Promise<unknown> {
        const res = await this.cmdApi.execPost({
            execPostRequest: {
                token: this.proxyToken,
                id: this.connId,
                args,
            },
        });
        return res;
    }

    coreCommand(): CoreCommand {
        return new CoreCommand(this);
    }

    strCommand(): StrCommand {
        return new StrCommand(this);
    }

    hashCommand(): HashCommand {
        return new HashCommand(this);
    }

    setCommand(): SetCommand {
        return new SetCommand(this);
    }

    listCommand(): ListCommand {
        return new ListCommand(this);
    }

    sortedSetCommand(): SortedSetCommand {
        return new SortedSetCommand(this);
    }
}

export async function listClient(proxyAddr: string, proxyToken: string): Promise<RedisClient[]> {
    const cfg = new Configuration({ basePath: `http://${proxyAddr}` });
    const connectionApi = new ConnectionApi(cfg);
    const infoList = await connectionApi.listPost({
        listPostRequest: {
            token: proxyToken,
        },
    });
    return infoList.map(item => new RedisClient(proxyAddr, proxyToken, item.id, item.name, item.db));
}